package com.service.socket.process;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.jboss.netty.channel.Channel;

import com.service.bean.Road_GpsSignal;
import com.service.bean.Road_GpsSignal_Dumper;
import com.service.bean.Road_GpsSignal_Paver;
import com.service.bean.Road_GpsSignal_Roller;
import com.service.bean.other.VehicleScalar;
import com.service.bean.signal.GpsHookArmCaseSignal;
import com.service.bean.signal.GpsSignal;
import com.service.cache.CacheManager;
import com.service.calculate.Road_BasalCalculator_Dumper;
import com.service.calculate.Road_BasalCalculator_Paver;
import com.service.calculate.Road_BasalCalculator_Roller;
import com.service.calculate.Road_ProcessPool;
import com.service.calculate.Road_SignalCreator;
import com.service.calculate.Road_StatusCalculator;
import com.service.calculate.hookArmCase.HookArmCaseSignalCreator;
import com.service.calculate.vehicle.ProcessPool;
import com.service.calculate.vehicle.SignalCreator;
import com.service.other.Logger;
import com.service.other.ServerConfig;
import com.service.socket.protocol.CmdWord;
import com.service.socket.protocol.Packet;
import com.service.socket.protocol.Road_DataProtocol_Dumper;
import com.service.socket.protocol.Road_DataProtocol_Paver;
import com.service.socket.protocol.Road_DataProtocol_Roller;
import com.service.tools.Tools;

/**
 * B0指令，数据传输 
 * @author sxc
 *
 */
public class R_Class_B0 extends R_Class_Abstract {

	private VehicleScalar vehicleScalar = null;

	public R_Class_B0(Channel channel, Packet packet) {
		super(channel, packet);
		//一辆车一个对应的bean
		if(!CacheManager.instance().scalarCalers.containsKey(packet.getDeviceNo())){
			CacheManager.instance().scalarCalers.put(packet.getDeviceNo(), new VehicleScalar());
		}
		vehicleScalar = CacheManager.instance().scalarCalers.get(packet.getDeviceNo());	
		if (CacheManager.instance().vehicleMap.containsKey(packet.getDeviceNo())) {
			vehicle = CacheManager.instance().getVehicle(packet.getDeviceNo());							
		} else {
			hookArmCase = CacheManager.instance().getHookArmCase(packet.getDeviceNo());
		}
	}

	@Override
	public void execute() {
		//System.out.println("dtu -> server : " + packet.toString());
		try {
			int cmdword = Integer.parseInt(packet.cmdWord, 16);
			switch (cmdword) {
			case 0x08:
				// 运料车
				method_Road();
				break;
			case 0x09:
				// 摊铺机
				method_Road();
				break;
			case 0xA0:
				// 压路机
				method_Road();
				break;
			default:
				if (null != vehicle) {
					setData();
				} else if (null != hookArmCase) {
					setHookArmCaseData();
				} else {
					packet.status = CmdWord.STATUS_FAIL;
					packet.dataArea = null;
					SendCommand.replyDtu(channel, packet);
					Logger.err("device [" + packet.getDeviceNo() + "] process fail : vehicle no bind");
				}
				break;
			}
		} catch (Exception e) {
			Logger.err(e);
		}		
	}
	
	/**
	 * 车辆
	 */
	private void setData(){
		if(vehicle == null){
			 //Gps未绑定车辆
			packet.status = CmdWord.STATUS_FAIL;
			packet.dataArea = null;
			SendCommand.replyDtu(channel,packet);
			Logger.err("device ["+packet.getDeviceNo()+"] process fail : vehicle no bind");
			return;
		}
		if (!packet.isCrcValid()){
			//CRC校验失败
			packet.status = CmdWord.STATUS_FAIL;
			packet.dataArea = null;
			SendCommand.replyDtu(channel,packet);
			Logger.err("device ["+packet.getDeviceNo()+"] process fail on [CrcValid]:" + packet.isCrcValid());
			Logger.err(packet.toString());
			return;
		}

		//转发给监控器
		SendCommand.sendCtrlDtu(packet);
		//数据接收成功
		Packet bean = (Packet) packet.clone();
		bean.status = CmdWord.STATUS_SUCCESS;
		bean.dataArea = null;
		SendCommand.replyDtu(channel,bean);
					
		//获得signal对象
		SignalCreator creator = new SignalCreator(packet.dataArea,packet.getDeviceNo());			
		GpsSignal signal = creator.createSignal();
		if(signal.lat == 0 || signal.lng == 0){
			//无效数据也提供给前端
			signal.gpsTime = new Date();
			vehicle.setLastGps_lastest(signal);				
			Logger.err("device ["+packet.getDeviceNo()+"] process fail : lat or lng = 0");
			return;
		}

		long longTime = 0;
		if(vehicle.lastGps_Received != null){
			longTime = Math.abs(Tools.getTimeLong(signal.gpsTime, vehicle.lastGps_Received.gpsTime));
		}
		//数据区放入队列
		offerSignalQueue(signal);
		//确认实时数据件数并进行计算
		if(checkRealTimeWithScalarCal(packet.getDeviceNo(),signal.dataTypes,longTime)){
			ProcessPool.scalarCal(vehicleScalar, packet.getDeviceNo());
		}else{
			vehicle.setLastGps_lastest(signal);
		}
		
		//终端发过来的最新数据，用来计算和上一条的间隔时间
		vehicle.lastGps_Received = signal;
	}
	
	/**
	 * 勾臂车箱体
	 */
	private void setHookArmCaseData() {
		if (hookArmCase == null) {
			 //Gps未绑定车辆
			packet.status = CmdWord.STATUS_FAIL;
			packet.dataArea = null;
			SendCommand.replyDtu(channel,packet);
			Logger.err("hook arm vehicle ["+packet.getDeviceNo()+"] process fail : vehicle no bind");
			return;
		}
		if (!packet.isCrcValid()) {
			//CRC校验失败
			packet.status = CmdWord.STATUS_FAIL;
			packet.dataArea = null;
			SendCommand.replyDtu(channel,packet);
			Logger.err("hook arm vehicle ["+packet.getDeviceNo()+"] process fail on [CrcValid]:" + packet.isCrcValid());
			Logger.err(packet.toString());
			return;
		}
		//转发给监控器
		SendCommand.sendCtrlDtu(packet);
		//数据接收成功
		Packet bean = (Packet) packet.clone();
		bean.status = CmdWord.STATUS_SUCCESS;
		bean.dataArea = null;
		SendCommand.replyDtu(channel,bean);
		
		// 获取Signal对象
		HookArmCaseSignalCreator creator = 
				new HookArmCaseSignalCreator(packet.dataArea, packet.getDeviceNo());
		GpsHookArmCaseSignal signal = creator.createSignal();
		if (signal.lng == 0 || signal.lat == 0) {
			signal.gpsTime = new Date();
			hookArmCase.setLastGps_lastest(signal);
			Logger.err("hook arm vehicle ["+packet.getDeviceNo()+"] process fail : lat or lng = 0");
			return;
		}

		//计算和上一条的间隔时间
		long longTime = 0;
		if(hookArmCase.lastGps_Received  != null){
			longTime = Math.abs(Tools.getTimeLong(signal.gpsTime, hookArmCase.lastGps_Received.gpsTime));
		}
		
		// 数据区放入队列
		CacheManager.instance().getHookArmSignalQueue(packet.getDeviceNo()).offer(signal);
		//确认实时数据件数并进行计算
		if(checkRealTimeWithScalarCal(packet.getDeviceNo(),signal.dataTypes,longTime)){
			//启动ScalarCal计算
			ProcessPool.scalarCal(vehicleScalar, packet.getDeviceNo());
		}else{
			//更新最新时间的signal信号数据
			hookArmCase.setLastGps_lastest(signal);
		}		
		
		//终端发过来的最新数据，用来计算和上一条的间隔时间
		hookArmCase.lastGps_Received = signal;
	}

	
	/**
	 * 判定是否启动正式计算
	 * @param deviceNo
	 * @param dataTypes <pre> 0：历史数据 </br>1：实时数据</pre>
	 * @param longTime
	 */
	public boolean checkRealTimeWithScalarCal(String deviceNo, Integer dataTypes, long longTime) {
		
		synchronized(vehicleScalar){
			//判断数据类型（0：历史数据， 1：实时数据）|| 如果和上一条间隔时间超过60秒（计数清0）
			if(dataTypes==0 || longTime >  ServerConfig.instance().intervaltime){
				//出现历史数据，累计数清0
				vehicleScalar.realAdd =0;
			}else{
				//出现实时数据，开始累计（累计数不超过3）
				if (vehicleScalar.realAdd < 3){
					vehicleScalar.realAdd++;
				}				
			}
			//连续实时数据=3件的场合，启动计算
			if(vehicleScalar.realAdd == 3){
				return true;
			}			
		}
		return false;
	}

	private void offerSignalQueue(GpsSignal signal) {
		// 默认第一条上来的数据油箱高度不为零为正常油位
		if (CacheManager.instance().oilNormal.get(signal.equipmentId) == null) {
			if (signal.oilHeight > 0) {
				CacheManager.instance().oilNormal.put(signal.equipmentId, signal);
			}
			CacheManager.instance().getSignalQueue(packet.getDeviceNo()).offer(signal);
			return;
		}
		double deffHeight = CacheManager.instance().oilNormal.get(signal.equipmentId).oilHeight - signal.oilHeight;
		// 异常油位列表
		List<GpsSignal> listAbnormal = CacheManager.instance().oilAbnormal.get(signal.equipmentId);
		if (listAbnormal == null) {
			listAbnormal = new ArrayList<GpsSignal>();
		}
		// 判断异常油位(突升或突降),否则为正常
		if (deffHeight <= ServerConfig.instance().oilJump || deffHeight >= ServerConfig.instance().oilDump) {
			listAbnormal.add(signal);
			// 判断连续N条(设定值)突变认为正常数据,否则插入异常队列
			if (listAbnormal.size() == ServerConfig.instance().thresholdNum) {
				for (int i = 0; i < listAbnormal.size(); i++) {
					CacheManager.instance().getSignalQueue(listAbnormal.get(i).gpsNo).offer(listAbnormal.get(i));
				}
				// 更新最新正常队列
				CacheManager.instance().oilNormal.put(signal.equipmentId, signal);
				// 清空异常队列
				CacheManager.instance().oilAbnormal.remove(signal.equipmentId);
			} else {
				//进入异常管道的时候，要更新缓存 
				vehicle.setLastGps_lastest(signal);
				CacheManager.instance().oilAbnormal.put(signal.equipmentId, listAbnormal);
			}
		} else {
			// 判断有突变将重新计算
			if (listAbnormal.size() > 0) {
				double avgheight = (CacheManager.instance().oilNormal.get(signal.equipmentId).oilHeight + signal.oilHeight) / 2;
				for (int i = 0; i < listAbnormal.size(); i++) {
					GpsSignal s = listAbnormal.get(i);
					s.oilHeight = avgheight;
					// 放入队列
					CacheManager.instance().getSignalQueue(s.gpsNo).offer(s);
				}
				// 当前数据放入队列
				CacheManager.instance().getSignalQueue(packet.getDeviceNo()).offer(signal);
				// 更新正常油感缓存
				CacheManager.instance().oilNormal.put(signal.equipmentId, signal);
				// 清空异常队列
				CacheManager.instance().oilAbnormal.remove(signal.equipmentId);
			} else {
				// 当前数据放入队列
				CacheManager.instance().getSignalQueue(packet.getDeviceNo()).offer(signal);
				// 更新正常油感缓存
				CacheManager.instance().oilNormal.put(signal.equipmentId, signal);
			}
		}
	}

	private void method_Road(){
		this.road_vehicle = CacheManager.instance().getVehicle_Road(packet.getDeviceNo());
		if(road_vehicle == null){
			 //Gps未绑定车辆
			packet.status = CmdWord.STATUS_FAIL;
			packet.dataArea = null;
			SendCommand.replyDtu(channel,packet);
			Logger.err("device ["+packet.getDeviceNo()+"] process fail : vehicle no bind");
			return;
		}
		if (!packet.isCrcValid()){
			//CRC校验失败
			packet.status = CmdWord.STATUS_FAIL;
			packet.dataArea = null;
			SendCommand.replyDtu(channel,packet);
			Logger.err("device ["+packet.getDeviceNo()+"] process fail on [CrcValid]:" + packet.isCrcValid());
			Logger.err(packet.toString());
			return;
		}
		Road_GpsSignal signal = getGpsSignal();
		if(signal == null){
			//命令字不对
			packet.status = CmdWord.STATUS_FAIL;
			packet.dataArea = null;
			SendCommand.replyDtu(channel,packet);
			Logger.err("device ["+packet.getDeviceNo()+"] process fail : getGpsSignal fail");
			return;
		}
		
		//转发给监控器
		SendCommand.sendCtrlDtu(packet);
		//数据接收成功
		Packet bean = (Packet) packet.clone();
		bean.status = CmdWord.STATUS_SUCCESS;
		bean.dataArea = null;
		SendCommand.replyDtu(channel,bean);

		if(signal.lat == 0 || signal.lng == 0){
			//无效数据也提供给前端
			signal.gpsTime = new Date();	
			//更新最新时间的signal信号数据
			road_vehicle.setLastGps_lastest(signal);
			Logger.err("device ["+packet.getDeviceNo()+"] process fail : lat or lng = 0");
			return;
		}
		
		//数据区放入队列
		CacheManager.instance().getSignalQueue_Road(packet.getDeviceNo()).offer(signal);			
		Road_ProcessPool.scalarCal(vehicleScalar, packet.getDeviceNo());
		//终端发过来的最新数据，用来计算和上一条的间隔时间
		road_vehicle.lastGps_Received = signal;

	}
	
	private Road_GpsSignal getGpsSignal(){
		//获得signal对象
		Road_GpsSignal signal = null;
		String version = "";
		if(Integer.parseInt(packet.cmdWord, 16) == 0x08){
			// 运料车
			Road_SignalCreator creator = new Road_SignalCreator(packet.dataArea,packet.getDeviceNo(),
					new Road_GpsSignal_Dumper(),new Road_BasalCalculator_Dumper(),
					new Road_StatusCalculator(),new Road_DataProtocol_Dumper(version));
			signal = creator.createSignal();
		}else if(Integer.parseInt(packet.cmdWord, 16) == 0x09){
			// 摊铺机
			Road_SignalCreator creator = new Road_SignalCreator(packet.dataArea,packet.getDeviceNo(),
					new Road_GpsSignal_Paver(),new Road_BasalCalculator_Paver(),
					new Road_StatusCalculator(),new Road_DataProtocol_Paver(version));
			signal = creator.createSignal();
		}else if(Integer.parseInt(packet.cmdWord, 16) == 0xA0){
			// 压路机
			Road_SignalCreator creator = new Road_SignalCreator(packet.dataArea,packet.getDeviceNo(),
					new Road_GpsSignal_Roller(),new Road_BasalCalculator_Roller(),
					new Road_StatusCalculator(),new Road_DataProtocol_Roller(version));
			signal = creator.createSignal();
		}
		return signal;
	}
}
